#/usr/bin/env python
"""
Stores all of the different NPC/PC for the game
"""
import setup
from lib import dmath
import pygame
import math as m
from pygame.locals import *

DEBUG = False

#classes for our game objects

# base classes
class Actor(pygame.sprite.Sprite):
    def __init__(self, sprite_name):
        pygame.sprite.Sprite.__init__(self) #call Sprite initializer

        if DEBUG:
            """ Skip remaining initialization if no sprite name given. """
            if sprite_name == None:
                self.image, self.rect = None, Rect(0,0,5,5)
                return

        self.image, self.rect = setup.load_image(sprite_name, -1)

    def get_pos(self):
        return self.rect.center


class Mob(Actor):
    """moves a sprite on the screen"""
    def __init__(self, sprite_name):
        Actor.__init__(self, sprite_name)

    def getX(self):
        return self.get_pos()[0]

    def getY(self):
        return self.get_pos()[1]

    def move_abs(self, xy):
        self.rect.center = xy

    def move_inc(self, xy):
        newpos = self.rect.move(xy)
        self.rect = newpos

    def stop(self):
        """ Stop doing what you were doing. """
        pass

# subclasses

def cheatCopy(frm):
    to = []
    for a in frm:
        to.append(a)
    return to

DISTANCE = 0
VELOCITY = 1
ACCELERATION = 2

class Car(Mob):
    def DEBUGcheck(self):
        try:
            print "%s\tis following\t%s"%(self.DEBUGname, self.toFollow.DEBUGname)
        except:
            print "DEBUGcheck failed"

    def __init__(self, image, toFollow, initials, desired):
        Actor.__init__(self, image)
        self.toFollow = toFollow
        self.actual = cheatCopy(initials)
        self.desired = cheatCopy(desired)

        # DEBUG
        self.DEBUGname = image
        self.DEBUGcheck()

    def getLeaderVelocity(self):
        """ Ask who we're following for leader's velocity """
        return self.toFollow.getLeaderVelocity()

    def makeRelativeVelocity(self):
        """ Modify my velocity to make relative to leader """
        self.actual[VELOCITY] -= self.getLeaderVelocity()

    def updateDistance(self):
        """
        Car.updateDistance() -> int
        Update the distance between our car and the car to follow.
        Result is how far behind we are.

        >>> lead = Car(None, None, (0,0,0), (1,1,0))
        >>> tail = Car(None, lead,   (0,0,0), (1,1,0))
        >>> lead.move_abs( (200,100) )
        >>> tail.move_abs( (100,100) )
        >>> tail.updateDistance()
        >>> print tail.actual
        [100, 0, 0]
        >>> print tail.actual[DISTANCE]
        100
        """
        self.actual[DISTANCE] = self.toFollow.getX() - self.getX() 

    def accelerate(self):
        """
        If we are too far away, increase acceleration. If too close, decrease.

        >>> c = Car(None, None, (0,0,0), (1,1,0))
        >>> c.accelerate()
        >>> print c.actual
        [0, 0, 1]
        >>> print c.actual[ACCELERATION]
        1
        """
        self.actual[ACCELERATION] += cmp( self.desired[DISTANCE], self.actual[DISTANCE])
        self.actual[ACCELERATION] = dmath.clamp(self.actual[ACCELERATION], -5, 5)

    def updateVelocity(self):
        """
        Apply the acceleration to the velocity.

        >>> c = Car(None, None, (0,0,1), (1,1,0))
        >>> c.updateVelocity()
        >>> print c.actual
        [0, 1, 1]
        >>> print c.actual[VELOCITY]
        1
        """
        self.actual[VELOCITY] += self.actual[ACCELERATION]
        self.makeRelativeVelocity()
        self.actual[VELOCITY] = dmath.clamp(self.actual[VELOCITY], 0, 5)

    def updateLocation(self):
        """ Apply Motion to car.  """
        self.move_inc( (self.actual[VELOCITY],0) )
        if self.getX() > 1024:
            self.move_abs( (1024, self.getY()) )

    def update(self):
        """ Change the velocity to match the desired.
        TODO: This should actually change the velocity to attain the desired
        distance.
        """
        # look around and react
        self.updateDistance()
        self.accelerate()

        # fixup

        # update for the frame
        self.updateVelocity()
        self.updateLocation()

class FakeCar(Car):
    def __init__(self, initials, desired):
        Car.__init__(self, 'blank_car.jpg', None, initials, desired)

    def getLeaderVelocity(self):
        return self.actual[VELOCITY]

    def update(self):
        """ Change the velocity to match the desired.
        TODO: This should actually change the velocity to attain the desired
        distance.
        """
        Car.update(self)
        self.actual = self.desired

    def setTail(self, myTail):
        self.toFollow = myTail

        



def _test():
    """ Run unit tests. """
    import doctest
    doctest.testmod()

if __name__ == "__main__":
    """ If script is run directly, then run unit tests """
    DEBUG = True
    _test()
